import {
    Matrix4
} from "three";


interface shaderConfig {
    vs: string;
    fs: string;
    shaderName: string;
    attribs: vertexBuffer[];
    unifroms: [];
    mode: GPUPrimitiveTopology;
    // ["point-list", "line-list", "line-strip", "triangle-list", "triangle-strip"]
}

interface vertexBuffer {
    size: GPUVertexFormat;
    location: number;
    //_size: number;
}

export default class Poly {

    domElement: HTMLCanvasElement;
    device?: GPUDevice;
    commandEncoder?: GPUCommandEncoder;
    renderPass?: GPURenderPassEncoder;
    clearColor: GPUColor;

    private pipelineMap: Map<string, GPURenderPipeline> = new Map();

    public constructor(canvas: HTMLCanvasElement, color: GPUColor = { r: 0, g: 0, b: 0, a: 1 }) {
        this.domElement = canvas;
        this.clearColor = color;

        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;

        if (!navigator.gpu) {
            console.log('当前浏览器不支持WebGPU');
            return;
        }

    }

    public async init() {
        const { domElement: canvas, clearColor } = this;

        //浏览器请求GPU适配器
        const adapter = await navigator.gpu.requestAdapter();
        //获取GPU设备对象, 通过GPU设备镀锡device的WebGPU API可以控制GPU的渲染过程
        const device = await adapter?.requestDevice() as GPUDevice;

        const context = canvas.getContext('webgpu')!;
        const format = navigator.gpu.getPreferredCanvasFormat();//颜色数据
        context?.configure({
            device: device,//GPU对象
            format: format,//颜色数据
        });


        // 创建命令编码器
        const commandEncoder = device.createCommandEncoder();
        // 创建渲染通道对象
        const renderPass = commandEncoder.beginRenderPass({
            colorAttachments: [
                {
                    //指向用于Canvas画布纹理视图对象(Canvas对应的缓冲区)
                    //该渲染管道renderPass输出的像素会存储到Canvas对应的颜色缓冲区
                    view: context.getCurrentTexture().createView(),
                    storeOp: 'store',//像素数据写入颜色缓冲区
                    loadOp: 'clear',//每次渲染前执行清除?
                    clearValue: clearColor,//背景颜色
                }
            ]
        });
        this.device = device;
        this.commandEncoder = commandEncoder;
        this.renderPass = renderPass;
    }

    public loadShader(config: shaderConfig) {
        const { device, pipelineMap } = this;
        const { vs, fs, shaderName, attribs, unifroms, mode } = config;


        const vsM = device!.createShaderModule({ code: vs });
        const fsM = device!.createShaderModule({ code: fs });


        const buffers: Array<GPUVertexBufferLayout> = [];
        attribs.forEach(u => {
            const { size, location } = u;
            let _size = 1;
            if (size.lastIndexOf('x') != -1) {
                _size = Number(size.substring(size.length - 1, size.length));
            }
            buffers.push({
                arrayStride: _size * 4,       //一个顶点数据占用的字节长度(三维 * 4)
                attributes: [{
                    shaderLocation: location,   //GPU显存是顶点缓冲区标记存储位置
                    format: size,               //格式: float32x3表示一个顶点数据包含3个3
                    offset: 0                   //偏移量?    
                }],
            });
        });

        // 创建渲染管线
        const pipeline = device!.createRenderPipeline({
            vertex: {//顶点作色器
                module: vsM,
                entryPoint: 'main',//入口函数
                buffers: buffers
            },
            fragment: {//片元作色器
                module: fsM,
                entryPoint: 'main',//入口函数
                targets: [{
                    format: navigator.gpu.getPreferredCanvasFormat(),
                }]
            },
            primitive: {
                topology: mode,//绘制三角形
            },
            layout: 'auto',
        });

        pipelineMap.set(shaderName, pipeline);
    }

    public setAttrib(shaderName: string, val: [{ location: number, array: Float32Array }]) {
        const { device, renderPass, pipelineMap } = this;

        const pipeline = pipelineMap.get(shaderName);
        if (pipeline) {
            renderPass!.setPipeline(pipeline);

            val.forEach(u => {
                const { array, location } = u;
                const verticesBuffer = device!.createBuffer({
                    //缓冲区字节长度
                    size: array.byteLength,
                    //设置该缓冲区的用途()
                    usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST
                });
                device!.queue.writeBuffer(verticesBuffer, 0, array);
                renderPass!.setVertexBuffer(location, verticesBuffer);
            });

        } else {
            console.log(`pipelineMap不存在[${shaderName}]对象`);
        }
    }

    public draw(count: number) {
        const { device, renderPass, commandEncoder } = this;
        renderPass!.draw(count);
        renderPass!.end();

        //创建命令缓冲区
        const commandBuffer = commandEncoder!.finish();
        //生成GPU指令存入缓冲区
        device!.queue.submit([commandBuffer]);
    }
}